#pragma once

#include "transformable.h"
#include <osg\Vec3>
#include <osg\Vec4>
#include <osg\BoundingBox>
#include <osg\NodeCallback>
#include <osg\StateSet>
#include <osg\CullFace>
#include <osg/MatrixTransform>
#include "corebase_global.h"
#include <osg\Geode>
#include <osg\Geometry>

namespace osg
{
	template<class T> class ref_ptr;
	class Box;
	class PositionAttitudeTransform;
	class Material;
	class ShapeDrawable;
}

namespace CoreBase
{
	class ActorBase;
}

namespace CoreBase
{
	class CommonShape
	{
	public:
		CommonShape();
		~CommonShape(){}
		virtual void updateSize(){}
		virtual void startShow(){}
		virtual void setRadious(float radious){}
		virtual void setHeight(float height){}
		int getCommonShapeType()
		{
			return _type;
		}
		virtual void setColor(const osg::Vec4&){}
	protected:
		int _type;
		osg::ref_ptr<osg::StateSet>					_defaultStateSet;
		osg::ref_ptr<osg::StateSet>					_lineModeStateSet;
	};

	class ShapeSizeUpdateCallback : public osg::NodeCallback
	{
	public:
		ShapeSizeUpdateCallback(CommonShape* cs)
		{
			_cs = cs ;
		}
		~ShapeSizeUpdateCallback(){} ;
		virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
		{
			if( !_cs )
			{
				traverse(node,nv);
				return;
			}
			_cs->updateSize();
			//if(_nestedCallback.valid())
			//	 (*_nestedCallback)(node,nv);
			traverse(node,nv);
		}
	protected:
		CommonShape*				_cs ;
	};

	class COREBASE_EXPORT CommonShapeBox : public CoreBase::Transformable,public CommonShape
	{
	public:
		CommonShapeBox(int type,CoreBase::ActorBase* owneractor,const QString& name = "CommonShapeBox");
		CommonShapeBox(int type,osg::MatrixTransform& node,CoreBase::ActorBase* owneractor,const QString& name = "CommonShapeBox");

		void createBox(osg::BoundingBox& box,float heightpercent,const osg::Vec4& color,bool opacity);
		void createBox(const osg::Vec3& center,float bottomz,float x,float y,float z,const osg::Vec4& color,bool opacity);
		virtual void startShow();
		void updateSize();
		virtual void setColor(const osg::Vec4&);
		virtual osg::Node* getOSGNode();
		virtual const osg::Node* getOSGNode() const;
		void setSize(float x,float y,float z);
		virtual void setRadious(float radious);
		virtual void setHeight(float height);
	protected:
		virtual ~CommonShapeBox();
		osg::ref_ptr<osg::PositionAttitudeTransform>		_boxTransform;
		osg::ref_ptr<osg::Box>								_pBox;
		osg::ref_ptr<osg::Box>								_pLineBox;
		osg::ref_ptr<osg::ShapeDrawable>					_boxShape;
		osg::ref_ptr<osg::ShapeDrawable>					_lineBoxShape;
		osg::Vec3											_center;
		osg::Vec4											_color;
		bool												_opacity;
		float												_x;
		float												_y;
		float												_z;
		float												_scalZ;
		float												_bottomZ;
		bool												_startShow;
	};

	class COREBASE_EXPORT LineRectShape : public CoreBase::Drawable
	{
	public:
		LineRectShape(bool hud = true);
		void updateSize(const osg::Vec3& base,int w, int l,bool corner = true);
		void update();
		osg::Node* getOSGNode();
		const osg::Node* getOSGNode() const;
		void viewResize(const int w,const int h);
	protected:
		virtual ~LineRectShape(){};
		void createHudCamera();
		osg::Group* createRealNode(const osg::Vec3& base,float width,float length,int plane,const osg::Vec4& color,bool corner = true);
		osg::ref_ptr<osg::Geode>							_realnode;
		osg::ref_ptr<osg::Geometry>							_realgeo ;
	private:
		bool												_isupdateSize;
		std::vector<osg::Vec3>								_vsets  ;
		osg::Vec3											_vbase;
		int													_plane;
		osg::ref_ptr<osg::Vec3Array >						cvertex ;
		osg::ref_ptr<osg::DrawElementsUInt>					indexset ;
		osg::ref_ptr<osg::Vec4Array>						_colorsData ;
		osg::ref_ptr<osg::Camera>							_hudCamera;
		bool												_isHud;
		osg::ref_ptr<osg::MatrixTransform>					_transformNode ;
	};

	class LineRectUpdateCallback : public osg::NodeCallback
	{
	public:
		LineRectUpdateCallback(LineRectShape* linerect ) {

			_linerect = linerect ;
		}
		~LineRectUpdateCallback() {} ;

		virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
		{
			if( _linerect)
			{
				_linerect->update() ;
			}
		}
	private:
		LineRectShape * _linerect ;
	} ;

	class COREBASE_EXPORT CircleShape : public CoreBase::Drawable
	{
	public: 
		CircleShape(const osg::Vec3& center,float radius,int slice,
			float width=2.0,const osg::Vec4& color=osg::Vec4(1.0,0.0,0.0,1.0), osg::StateSet* ss=0 );
		void update() ;
		void reDraw(const osg::Vec3&center,float radius,int slice);
		void setCenter(const osg::Vec3 &point ) ;
		osg::Vec3 getCenter();
		void setRadius(float& radius);
		float getRadius();
		void setSlice( int &number) ;
		int getSlice();
		void setWidth(float &width);
		float getWidth();
		void setColor(const osg::Vec4& color ) ;
		osg::Vec4 getColor();
		void clear() ;
		osg::Node* getOSGNode();
		const osg::Node* getOSGNode() const;
	protected:
		virtual ~CircleShape() {};
		osg::ref_ptr<osg::MatrixTransform>						_transformNode ;
		osg::ref_ptr<osg::Geode>								_gNode ; 
		osg::ref_ptr<osg::Geometry>								_geode; 
		osg::ref_ptr<osg::Vec3Array>							_vArray; 
		osg::ref_ptr<osg::Vec4Array>							_cArray ;
	private:
		float													_radius ;
		int														_slice;
		osg::Vec3												_center ;
		osg::Vec4												_color ;
		float													_width;
	};

	class COREBASE_EXPORT PlaneShape : public CoreBase::Drawable
	{
	public: 
		PlaneShape();
		void reset(const osg::Vec3& p1,const osg::Vec3& p2,const osg::Vec3& p3,
			const osg::Vec2& t1,const osg::Vec2& t2,const osg::Vec2& t3,osg::StateSet* ss=0);
		void reset(const osg::Vec3& p1,const osg::Vec3& p2,const osg::Vec3& p3,const osg::Vec3& p4,
			const osg::Vec2& t1,const osg::Vec2& t2,const osg::Vec2& t3,const osg::Vec2& t4,osg::StateSet* ss=0);
		osg::Node* getOSGNode();
		const osg::Node* getOSGNode() const;
		void showPlaneLine(bool show);
		void updateLine(std::vector<osg::Vec3> pointvector);
		void setColor(const osg::Vec4& color);
		osg::Drawable* getPlaneAsDrawable();
	protected:
		virtual ~PlaneShape() {};
		void initDrawable();
		void clear();
		osg::ref_ptr<osg::MatrixTransform>						_transformNode ;
		osg::ref_ptr<osg::Geode>								_geode ; 
		osg::ref_ptr<osg::Geometry>								_geometry; 
		osg::ref_ptr<osg::Vec3Array>							_vArray; 
		osg::ref_ptr<osg::Vec2Array>							_tArray; 
		osg::ref_ptr<osg::Vec4Array>							_cArray ;
		bool													_showPlaneLine;
		osg::ref_ptr<osg::Geode>								_lineGeode ; 
		osg::ref_ptr<osg::Geometry>								_lineGeometry; 
		osg::ref_ptr<osg::Vec3Array>							_lineVArray; 
		osg::ref_ptr<osg::Vec4Array>							_lineCArray;
		std::vector<osg::Vec3>									_linePointVector;
	private:
		osg::Vec3												_p1;
		osg::Vec3												_p2;
		osg::Vec3												_p3;
		osg::Vec3												_p4;
		osg::StateSet*										_ss;
		osg::Vec4												_color;
	};

	class COREBASE_EXPORT UserDefineShape : public CoreBase::Transformable
	{
	public: 
		UserDefineShape(CoreBase::ActorBase* owneractor,float height = 2.0,const osg::Vec4& color=osg::Vec4(1.0,0.0,0.0,1.0));
		void setHeight(float height);
		float getHeight();
		void setColor(const osg::Vec4& color ) ;
		osg::Vec4 getColor();
		void clear();
		osg::Node* getOSGNode();
		const osg::Node* getOSGNode() const;
		void setUserDefineVertex(std::vector<osg::Vec3> vertexvector,bool end);
		void getUserDefineVertex(std::vector<osg::Vec3>& vertexvector);
		struct VertexStruct
		{
			int								_index;
			osg::Vec3						_point;
		};
	protected:
		virtual ~UserDefineShape() {};
		void initDrawable();
		void refreshTopPlane(std::vector<VertexStruct> vertexvector,bool iscounterclockwise);
		osg::ref_ptr<osg::MatrixTransform>						_transformNode ;
		osg::ref_ptr<osg::Geode>								_geode; 
		osg::ref_ptr<osg::Geometry>								_geomerty;
		osg::ref_ptr<osg::Vec3Array>							_vArray; 
		osg::ref_ptr<osg::Vec4Array>							_cArray;
		osg::ref_ptr<osg::DrawElementsUInt>						_indexSet;
		osg::ref_ptr<osg::DrawElementsUInt>						_topIndexSet;
		osg::ref_ptr<osg::Geode>								_lineGeode; 
		osg::ref_ptr<osg::Geometry>								_lineGeometry;
		osg::ref_ptr<osg::Vec3Array>							_lineVArray; 
		osg::ref_ptr<osg::Vec4Array>							_lineCArray;
		osg::ref_ptr<osg::DrawElementsUInt>						_lineIndexSet;
	private:
		std::vector<osg::Vec3>									_vertexVector;
		std::vector<VertexStruct>								_topVertexVector;
		osg::Vec3												_center ;
		osg::Vec4												_color ;
		float													_height;
	};

	class COREBASE_EXPORT CommonCylinder : public CoreBase::Transformable
	{
	public:
		CommonCylinder(CoreBase::ActorBase* owneractor,const QString& name = "CommonCylinder");
		virtual osg::Node* getOSGNode();
		virtual const osg::Node* getOSGNode() const;
		void setCylinderSetting(float radius,int facenum,const osg::Vec3& startp,
			float height,const osg::Vec4& color,bool withtop,bool withbottom,bool withcenter);
		osg::ref_ptr<osg::StateSet> getOrCreateTopStateSet();
		osg::ref_ptr<osg::StateSet> getOrCreateCenterStateSet();
		osg::ref_ptr<osg::StateSet> getOrCreateBottomStateSet();
	protected:
		virtual ~CommonCylinder();
		QVector<osg::Vec3> computePointVec(const osg::Vec3& centerpoint,float radius,int facenum
		,const osg::Vec3& mu,const osg::Vec3& mv);
		osg::ref_ptr<osg::PositionAttitudeTransform>			_boxTransform;
		osg::ref_ptr<osg::Geode>							_topGeode;
		osg::ref_ptr<osg::Geode>							_centerGeode;
		osg::ref_ptr<osg::Geode>							_bottomGeode;
		osg::ref_ptr<osg::Group>							_node;
		bool												_withTop;
		bool												_withBottom;
		bool												_withCenter;
	};
}	